Skip to content

fix(enroll): eighth audit — atomic age-keygen, sops validation, step-12 depth#180

Merged
mdheller merged 1 commit into
mainfrom
fix/enroll-eighth-audit
Jun 16, 2026
Merged

fix(enroll): eighth audit — atomic age-keygen, sops validation, step-12 depth#180
mdheller merged 1 commit into
mainfrom
fix/enroll-eighth-audit

Conversation

@mdheller

Copy link
Copy Markdown
Member

Findings and fixes

# Finding Severity Fix
1 gen_password output not validated for minimum length — tr -d can produce < 24 chars silently Low Assert ${#pw} -ge 16 before returning
2 age-keygen -o AGE_KEY is non-atomic — interrupted write leaves partial key; re-run sees it as present and fails age-keygen -y with no self-healing Medium Stdout capture > AGE_KEY.tmp + mv; adds stale .tmp cleanup at step start
3 sops --encrypt output not validated — exits 0 on some edge cases with empty output; empty ciphertext silently replaces secrets.yaml Medium [[ -s _SECRETS_TMP ]] before mv
4 Redundant chmod 600 after mv implies mv might change permissions Cosmetic Removed; note added explaining mv preserves source permissions
5 $(seq 1 12) and $(seq 1 6) fork subprocesses in tight polling loops Low {1..12} / {1..6} brace expansion
6 sops-nix-activate failure not detected in step 12 — oneshot stays failed not inactive; sourceos-syncd shows active but can never get its credential Medium systemctl is-failed --quiet sops-nix-activate check with targeted diagnostic
7 Katello containers not rechecked at step 12 — can be OOM-killed during nix build (steps 10–11); sourceos-syncd active but all Katello calls fail silently Medium docker ps --filter name=katello | wc -l at end of step 12
8 Unquoted ${KATELLO_ADMIN_PW_FILE} in banner() cat call Cosmetic Added quotes

Test plan

  • bash -n scripts/enroll.sh — no syntax errors
  • Kill age-keygen mid-write → re-run regenerates cleanly (no "key file may be corrupt" with partial file)
  • Force sops --encrypt to produce empty output → guard fires before mv
  • Simulate sops-nix-activate failure → step 12 shows FAILED with re-enroll instructions rather than generic "syncd not active"
  • Stop Katello containers during step 11 → step 12 warns "containers not running"
  • Full physical M2 enroll run (P0 test)

…12 depth

- gen_password: validate output >= 16 chars; tr -d can produce a short
  result on low-probability urandom runs; guard catches it before the
  password is written to files

- age-keygen atomic write: replace `age-keygen -o AGE_KEY` (truncate then
  write) with stdout capture to AGE_KEY.tmp then mv; interrupted write
  previously left a partial key that re-runs treated as present and then
  failed on age-keygen -y with a misleading "may be corrupt" message

- age-keygen stale .tmp cleanup: rm -f AGE_KEY.tmp at step 3 start,
  consistent with HW_CONFIG.tmp, ENROLL_NIX.tmp, MINISIGN_CACHE_INFO.tmp

- sops output non-empty check: [[ -s _SECRETS_TMP ]] before mv; sops
  exits 0 on some edge cases while producing empty output; empty ciphertext
  would silently replace secrets.yaml and loop on re-run

- Remove redundant chmod 600 after mv: mv preserves permissions from
  _SECRETS_TMP (created 600 via umask 077); the post-mv chmod was a no-op
  that implied mv might change permissions

- $(seq 1 N) → {1..N} brace expansion in both polling loops: eliminates
  subshell forks in tight 5s-interval loops (harmonia wait, syncd poll)

- sops-nix-activate failed-state check in step 12: oneshot services stay
  in 'failed' not 'inactive' when they error; distinguishes decryption
  failure from "still starting", with targeted re-enroll instructions

- Katello container liveness recheck in step 12: containers can be
  OOM-killed during nix build (steps 10-11); sourceos-syncd shows active
  but fails all Katello calls silently without this check

- Quote ${KATELLO_ADMIN_PW_FILE} in banner cat call: unquoted variable
  is inconsistent with quoting elsewhere; safe in practice but fragile
@mdheller mdheller merged commit efa2c58 into main Jun 16, 2026
@mdheller mdheller deleted the fix/enroll-eighth-audit branch June 16, 2026 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant